package Mongo;

import ConexionesBD.conexionBDMongo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import oracle.jdbc.OracleResultSet;

/**
 * Clase encargada de generar el script para Mongo
 * @author diegoojedagarcia
 */
public class CreaScriptMongo {
    
    private conexionBDMongo cbd;
    private Gson g;
    OracleResultSet rs;
    
    /**
     * Constructor de la clase
     * Crea el fichero scriptMongo.js con los datos necesarios para crear la base de datos en Mongo
     */
    public CreaScriptMongo(){
        FileWriter fichero = null;
        try {
            fichero = new FileWriter("scriptMongo.js");
            PrintWriter pw = new PrintWriter(fichero);
            ArrayList<Map<String, Object> > tab;
            g = new GsonBuilder().setPrettyPrinting().create();
            cbd = new conexionBDMongo();
            cbd.conectar();
            pw.append("db.esquemas.drop();\n");
            pw.append("db.entidades.drop();\n");
            pw.append("db.entidades_debiles.drop();\n");
            pw.append("db.atributos.drop();\n");
            pw.append("db.relaciones.drop();\n");
            pw.append("db.relacionesDebiles.drop();\n");
            pw.append("db.participaciones.drop();\n");
            rs = cbd.obtenerResultSet("SELECT * FROM esquema");
            tab = esquemaResultSetToListMap(rs);
            pw.append("db.esquemas.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("(SELECT nombre, nombre_esquema from tipo_entidad) MINUS (SELECT nombre, nombre_esquema FROM tipo_entidad_debil)");
            tab = tipoDatoResultSetToListMap(rs);
            pw.append("db.entidades.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("SELECT * from tipo_entidad_debil");
            tab = entidadDebilResultSetToListMap(rs);
            pw.append("db.entidades_debiles.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("SELECT * from atributos");
            tab = atributosResultSetToListMap(rs);
            pw.append("db.atributos.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("(SELECT * FROM tipo_relacion) MINUS (SELECT nombre, nombre_esquema from tipo_rel_ident)");
            tab = tipoDatoResultSetToListMap(rs);
            pw.append("db.relaciones.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("SELECT * FROM tipo_rel_ident");
            tab = tipoDatoResultSetToListMap(rs);
            pw.append("db.relacionesDebiles.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
            rs = cbd.obtenerResultSet("SELECT * FROM participa");
            tab = participaResultSetToListMap(rs);
            pw.append("db.participaciones.insert(");
            pw.append(g.toJson(tab));
            pw.append(");\n");
        } catch (SQLException ex) {
            System.out.println(ex.toString());
        } catch (IOException ex) {
            Logger.getLogger(CreaScriptMongo.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally{
            try {
                if (fichero != null)
                    fichero.close();
                if (rs != null)
                    rs.close();
            } catch (IOException ex) {
                Logger.getLogger(CreaScriptMongo.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SQLException ex) {
                Logger.getLogger(CreaScriptMongo.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Método que transforma la consulta de los esquemas a lenguaje Mongo
     * @param rs Objeto con el resultado de la consulta
     * @return ArrayList de map<String,Object>
     * @throws SQLException 
     */
    private ArrayList<Map<String, Object> > esquemaResultSetToListMap (OracleResultSet rs) throws SQLException{
        Map<String, Object> row;
        ArrayList<Map<String, Object > > tabla = new ArrayList<Map<String, Object>>();
        while (rs.next()){
            row = new HashMap<String, Object>();
            row.put("nombre", rs.getString("nombre"));
            tabla.add(row);
        }
        rs.close();
        return tabla;
    }
    
    /**
     * Método que transforma la consulta de los tipos de datos a lenguaje Mongo
     * @param rs Objeto con el resultado de la consulta
     * @return ArrayList de map<String,Object>
     * @throws SQLException 
     */
    private ArrayList<Map<String, Object> > tipoDatoResultSetToListMap (OracleResultSet rs) throws SQLException {
        Map<String, Object> row;
        ArrayList<Map<String, Object > > tabla = new ArrayList<Map<String, Object>>();
        while (rs.next()){
            row = new HashMap<String, Object>();
            row.put("nombre", rs.getString("nombre"));
            row.put("nombre_esquema", rs.getString("nombre_esquema"));
            tabla.add(row);
        }
        rs.close();
        return tabla;
    }
    
    /**
     * Método que transforma la consulta de los atributos a lenguaje Mongo
     * @param rs Objeto con el resultado de la consulta
     * @return ArrayList de map<String,Object>
     * @throws SQLException 
     */
    private ArrayList<Map<String, Object> > atributosResultSetToListMap(OracleResultSet rs) throws SQLException{
        Map<String, Object> row;
        ArrayList<Map<String, Object > > tabla = new ArrayList<Map<String, Object>>();
        while (rs.next()){
            row = new HashMap<String, Object>();
            row.put("nombre", rs.getString("nombre"));
            row.put("tipo_dato_pertenece", rs.getString("nombre_tipos_de_datos"));
            row.put("esquema", rs.getString("nombre_esquema"));
            row.put("multivaluado", rs.getInt("multivaluado"));
            row.put("derivado", rs.getInt("derivado"));
            row.put("tipo", rs.getString("tipo"));
            tabla.add(row);
        }
        rs.close();
        return tabla;
    }
    
    /**
     * Método que transforma la consulta de las entidades a lenguaje Mongo
     * @param rs Objeto con el resultado de la consulta
     * @return ArrayList de map<String,Object>
     * @throws SQLException 
     */
    private ArrayList<Map<String, Object> > entidadDebilResultSetToListMap (OracleResultSet rs) throws SQLException {
        Map<String, Object> row;
        ArrayList<Map<String, Object > > tabla = new ArrayList<Map<String, Object>>();
        while (rs.next()){
            row = new HashMap<String, Object>();
            row.put("nombre", rs.getString("nombre"));
            row.put("nombre_esquema", rs.getString("nombre_esquema"));
            row.put("nombre_rel_ident", rs.getString("nombre_tipo_rel_ident"));
            tabla.add(row);
        }
        rs.close();
        return tabla;
    }
    
    /**
     * Método que transforma la consulta de las participaciones de entidades en relaciones a lenguaje Mongo
     * @param rs Objeto con el resultado de la consulta
     * @return ArrayList de map<String,Object>
     * @throws SQLException 
     */
    private ArrayList<Map<String, Object> > participaResultSetToListMap (OracleResultSet rs) throws SQLException {
        Map<String, Object> row;
        ArrayList<Map<String, Object > > tabla = new ArrayList<Map<String, Object>>();
        while (rs.next()){
            row = new HashMap<String, Object>();
            row.put("nombre_entidad", rs.getString("nombre_entidad"));
            row.put("nombre_esquema", rs.getString("nombre_esquema"));
            row.put("nombre_relacion", rs.getString("nombre_relacion"));
            row.put("papel", rs.getString("papel"));
            row.put("cardMin", rs.getString("min"));
            row.put("cardMax", rs.getString("max"));
            tabla.add(row);
        }
        rs.close();
        return tabla;
    }
}
